package gat.application.dic.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.bitsun.core.common.exception.AppException;
import com.bitsun.core.common.exception.ErrorCode;
import com.bitsun.core.common.persistence.BasePService;
import com.bitsun.core.common.persistence.IPService;
import com.bitsun.core.common.persistence.Pager;
import com.bitsun.core.common.persistence.QueryParamUtils;
import com.google.common.base.CaseFormat;
import gat.application.dic.DicDataService;
import gat.convertor.dic.DicDataReqDtoConvertor;
import gat.convertor.dic.DicDataResDtoConvertor;
import gat.dto.req.dic.DicDataReqDto;
import gat.dto.req.dic.PromoActivityConfigReqDto;
import gat.dto.res.dic.DicDataResDto;
import gat.dto.res.dic.DicDataVo;
import gat.infrastructure.persistence.dao.dic.DicDataMapper;
import gat.infrastructure.persistence.po.dic.DicDataPo;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
 * 示例表，应用（业务编排）层实现
 * @author: tmac
 * @email: tmac
 */
@Slf4j
@Service("dicDataAppService")
@Transactional(rollbackFor = Exception.class)
public class DicDataServiceImpl implements DicDataService {

    @Autowired
    private DicDataReqDtoConvertor dicDataReqDtoConvertor;

    @Autowired
    private DicDataResDtoConvertor dicDataResDtoConvertor;

    private IPService<DicDataPo> dicDataPoService;

    @SuppressWarnings("SpringJavaAutowiringInspection")
    public DicDataServiceImpl(DicDataMapper dicDataMapper) {
        this.dicDataPoService = new BasePService(dicDataMapper);
    }



    @Override
    public DicDataResDto save(DicDataReqDto reqDto) {
        DicDataPo po = dicDataReqDtoConvertor.dto2Po(reqDto);
        dicDataPoService.save(po);
        DicDataResDto resDto = dicDataResDtoConvertor.po2Dto(po);
        return resDto;
    }

    @Override
    public boolean deleteByIds(String ids) {
        try {
            List<Long> idLongList =
            Arrays.asList(ids.split(",")).stream().map(s -> NumberUtils.createLong(s.trim())).collect(Collectors.toList());
            return dicDataPoService.removeByIds(idLongList);
        } catch (Exception e) {
            throw new AppException("参数错误：" + ids, ErrorCode.pc("417"), e);
        }
     }

    @Override
    public Pager<DicDataResDto> doPager(Map<String, Object> params) {
        Pager<DicDataPo> poPager = dicDataPoService.queryPage(params, DicDataPo.class);
        Pager<DicDataResDto> resDtoPager = dicDataResDtoConvertor.convertPoPager2ResDtoPager(poPager);
        return resDtoPager;
    }

    @Override
    public DicDataResDto selectOne(Long id) {
        DicDataPo po = dicDataPoService.getById(id);
        DicDataResDto resDto = dicDataResDtoConvertor.po2Dto(po);
        return resDto;
    }

    @Override
    public DicDataResDto selectOne(Map<String, Object> params) {
        QueryWrapper queryWrapper = QueryParamUtils.queryWrapper4eq(DicDataPo::new, params);
        queryWrapper.last(" limit 1");
        DicDataPo po = dicDataPoService.getOne(queryWrapper);
        DicDataResDto resDto = dicDataResDtoConvertor.po2Dto(po);
        return resDto;
    }

    @Override
    public boolean updateProps(Long id, Map<String, Object> params) {
        UpdateWrapper<DicDataPo> updateWrapper = QueryParamUtils.updateWrapper4Map(DicDataPo::new, id, params);
        return dicDataPoService.update(new DicDataPo(), updateWrapper);
        }

    @Override
    public boolean updateProps(Long id, DicDataReqDto reqDto) {

        //校验数据
        checkData(id,reqDto);

        DicDataPo po = dicDataReqDtoConvertor.dto2Po(reqDto);
        po.setId(id);
        return dicDataPoService.updateById(po);
    }

    private void checkData(Long id,DicDataReqDto reqDto) {

        DicDataPo byId = dicDataPoService.getById(id);
        //校验值
        if (Arrays.asList("seckillConfig","freeActivityConfig").contains(byId.getTypeCode())){
            //校验数据
            PromoActivityConfigReqDto configReqDto = JSON.parseObject(reqDto.getDescription(), PromoActivityConfigReqDto.class);
            if (configReqDto == null){
                throw new AppException("配置有误!");
            }
            if (!Arrays.asList("on","off").contains(configReqDto.getIsOpen())){
                throw new AppException("isOpen的值有误");
            }
            if (configReqDto.getGoodsNum() == null || configReqDto.getGoodsNum() < 0){
                throw new AppException("goodsNum的值有误");
            }
            if (configReqDto.getUserLimitNum() == null || configReqDto.getUserLimitNum() < 0){
                throw new AppException("userLimit的值有误");
            }
            if (configReqDto.getSeckillTime() == null || configReqDto.getSeckillTime().size() == 0){
                throw new AppException("seckillTime的值有误");
            }
            //校验时间段
            PromoActivityConfigReqDto.hasOverlap(configReqDto.getSeckillTime());

            //获取当前时间段
            LocalDateTime now = LocalDateTime.now();
            String currentTime = PromoActivityConfigReqDto.getCurrentTime(now, configReqDto.getSeckillTime());

            PromoActivityConfigReqDto configByTypeCode = JSON.parseObject(byId.getDescription(), PromoActivityConfigReqDto.class);

            String currentTime1 = PromoActivityConfigReqDto.getCurrentTime(now, configByTypeCode.getSeckillTime());

            if (currentTime1 != null && !currentTime1.equals(currentTime)){
                throw new AppException("正在进行中时间不能修改");
            }
        }
    }


    @Override
    public boolean updateAllProps(Long id, DicDataReqDto reqDto) {
        UpdateWrapper<DicDataPo> updateWrapper = Wrappers.update();
        updateWrapper.eq("id", id);
        Field[] fields = DicDataReqDto.class.getDeclaredFields();
        Arrays.stream(fields).filter(f -> !Modifier.isStatic(f.getModifiers())).forEach(field -> {
        try {
        PropertyDescriptor propertyDescriptor = new PropertyDescriptor(field.getName(), DicDataReqDto.class);
        Method getMethod = propertyDescriptor.getReadMethod();
        String fileNameCamel = getMethod.getName().substring(3);
        String fileNameUnderline = CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE, fileNameCamel);
        updateWrapper.set(fileNameUnderline, getMethod.invoke(reqDto));
        } catch (Exception ex) {
        log.warn("属性不存在get方法："+field.getName(),ex);
        }
        });
        return dicDataPoService.update(new DicDataPo(), updateWrapper);
    }

    @Override
    public List<DicDataVo> getByTypeCode(String code) {
        if (StringUtils.equals(code, "firstOrder")) {
            return getByTypeCodeByCache(code);
        }

        String[] codes = code.split(",");
        List<DicDataPo> list = dicDataPoService.list(new QueryWrapper<DicDataPo>().lambda().in(DicDataPo::getTypeCode,Arrays.asList(codes) )
                .orderByAsc(DicDataPo::getSort));
        return dicDataResDtoConvertor.poList2VoList(list);
    }

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Override
    public List<DicDataVo> getByTypeCodeByCache(String typeCode) {
        String[] codes = typeCode.split(",");
        List<DicDataVo> dicDataVos = new ArrayList<>();

        for (String code : codes) {
            String cache = stringRedisTemplate.opsForValue().get("hao6871:dicData:info:"+code);
            if (StringUtils.isNotBlank(cache)) {
                List<DicDataPo> dicDataPos = JSON.parseObject(cache, new TypeReference<List<DicDataPo>>() {});
                dicDataVos.addAll(dicDataResDtoConvertor.poList2VoList(dicDataPos));
            } else {
                dicDataVos.addAll(getByTypeCode(code));
            }
        }
        return dicDataVos;
    }

    @Override
    public PromoActivityConfigReqDto getActivityConfigByTypeCode(String typeCode) {
        DicDataPo dicDataPo = dicDataPoService.getOne(new LambdaQueryWrapper<DicDataPo>().eq(DicDataPo::getTypeCode, typeCode).last(" limit 1"));
        return JSON.parseObject(dicDataPo.getDescription(),PromoActivityConfigReqDto.class);
    }
}